package com.star.learn.excel.util;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import lombok.Data;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;

import java.io.File;
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;

/**
 * Excel大数据生成器优化版
 */
public class ExcelDataGenerator {

    /**
     * 学生实体类
     * */
    @ExcelIgnoreUnannotated
    @Data
    public static class StudentMoni {
        @ExcelProperty(index = 1, value = "学号")
        private String id;

        @ExcelProperty(index = 2, value = "姓名")
        private String name;

        @ExcelProperty(index = 3, value = "性别")
        private String gender;

        @ExcelProperty(index = 4, value = "班级")
        private String className;
    }

    /**
     * 数据缓存
     * */
    private static final String[] LAST_NAMES = {
            "李", "王", "张", "刘", "陈", "杨", "赵", "黄", "周", "吴",
            "徐", "孙", "胡", "朱", "高", "林", "何", "郭", "马", "罗"
    };

    private static final String[] FIRST_NAMES = {
            "伟", "芳", "娜", "秀英", "敏", "静", "丽", "强", "磊", "军",
            "洋", "勇", "艳", "杰", "娟", "涛", "明", "超", "秀兰", "霞"
    };

    private static final String[] DEPARTMENTS = {
            "计算机", "数学", "物理", "化学", "生物", "经济", "管理", "外语"
    };

    private static final String[] SPECIAL_CHARS = {"!", "@", "#", "$", "%", "&", "*"};

    private static final ThreadLocalRandom RANDOM = ThreadLocalRandom.current();

    /**
     * 数据生成方法
     * */
    private static String generateRandomId() {
        int length = RANDOM.nextInt(10, 16);
        StringBuilder sb = new StringBuilder(length);
        for (int i = 0; i < length; i++) {
            sb.append(RANDOM.nextInt(10));
        }
        return sb.toString();
    }

    private static String generateRandomName() {
        return LAST_NAMES[RANDOM.nextInt(LAST_NAMES.length)] +
                FIRST_NAMES[RANDOM.nextInt(FIRST_NAMES.length)];
    }

    private static String generateRandomGender() {
        return RANDOM.nextBoolean() ? "男" : "女";
    }

    private static String generateRandomClassName() {
        int year = RANDOM.nextInt(2020, 2025);
        int classNum = RANDOM.nextInt(1, 10);
        String department = DEPARTMENTS[RANDOM.nextInt(DEPARTMENTS.length)];
        return year + "级" + department + classNum + "班";
    }

    private static StudentMoni generateValidStudent() {
        StudentMoni student = new StudentMoni();
        student.setId(generateRandomId());
        student.setName(generateRandomName());
        student.setGender(generateRandomGender());
        student.setClassName(generateRandomClassName());
        return student;
    }

    private static StudentMoni generateInvalidStudent() {
        StudentMoni student = new StudentMoni();
        int invalidField = RANDOM.nextInt(3);

        student.setId(generateRandomId());
        student.setName(generateRandomName());
        student.setGender(generateRandomGender());
        student.setClassName(generateRandomClassName());

        switch (invalidField) {
            case 0 -> {
                // 学号太短
                int len = RANDOM.nextInt(1, 10);
                StringBuilder sb = new StringBuilder(len);
                for (int i = 0; i < len; i++) {
                    sb.append(RANDOM.nextInt(10));
                }
                student.setId(sb.toString());
            }
            case 1 -> {
                // 姓名带特殊字符
                String specialChar = SPECIAL_CHARS[RANDOM.nextInt(SPECIAL_CHARS.length)];
                student.setName(student.getName() + specialChar);
            }
        }

        return student;
    }

    /**
     * Excel 写入主逻辑
     * */
    public static void generateExcelFile(int totalCount, int batchSize, double invalidDataRatio, String dirPath) {
        File dir = new File(dirPath);
        if (!dir.exists() && !dir.mkdirs()) {
            throw new RuntimeException("目录创建失败: " + dirPath);
        }

        String fileName = "students_" + System.currentTimeMillis() + ".xlsx";
        String filePath = dirPath + File.separator + fileName;

        // 样式设置
        HorizontalCellStyleStrategy styleStrategy = createCellStyleStrategy();

        try (ExcelWriter excelWriter = EasyExcel.write(filePath, StudentMoni.class)
                .registerWriteHandler(styleStrategy)
                .relativeHeadRowIndex(4)
                .build()) {

            WriteSheet writeSheet = EasyExcel.writerSheet("学生信息").build();

            int totalBatches = (int) Math.ceil((double) totalCount / batchSize);

            for (int batch = 0; batch < totalBatches; batch++) {
                int currentBatchSize = Math.min(batchSize, totalCount - batch * batchSize);
                List<StudentMoni> batchData = new ArrayList<>(currentBatchSize);

                for (int i = 0; i < currentBatchSize; i++) {
                    batchData.add(RANDOM.nextDouble() < invalidDataRatio
                            ? generateInvalidStudent()
                            : generateValidStudent());
                }

                excelWriter.write(batchData, writeSheet);
                batchData.clear();

                System.out.printf("已生成: %d/%d 条 (%.2f%%)%n",
                        (batch + 1) * batchSize, totalCount,
                        100.0 * (batch + 1) * batchSize / totalCount);
            }

        } catch (Exception e) {
            System.err.println("写入Excel失败：" + e.getMessage());
        }

        System.out.println("Excel文件生成成功：" + filePath);
    }

    private static HorizontalCellStyleStrategy createCellStyleStrategy() {
        WriteCellStyle headStyle = new WriteCellStyle();
        headStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
        headStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());

        WriteCellStyle contentStyle = new WriteCellStyle();
        contentStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);

        return new HorizontalCellStyleStrategy(headStyle, contentStyle);
    }

    /**
     * 主函数
     * */
    public static void main(String[] args) {
        int totalCount = 100_000;  // Java7引入的数字字面量增强写法，让长数字更易读
        int batchSize = 1_000;
        double invalidDataRatio = 0.05;
        String outputDir = "D:\\ExcelMoni";

        generateExcelFile(totalCount, batchSize, invalidDataRatio, outputDir);
    }
}